/*
 * Copyright 2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.paboo.chart.datamatrix;

import com.google.gson.Gson;
import com.google.zxing.qrcode.encoder.ByteMatrix;
import org.paboo.codec.Base64;
import org.paboo.entity.ImageEntity;
import org.paboo.util.*;
import org.springframework.hateoas.ExposesResourceFor;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

/**
 * @author Leonard
 */
@RestController
@ExposesResourceFor(DmEntity.class)
public class DmController {

    private static final long serialVersionUID = 3525032759250925015L;
    private LoggerFactoryUtils log = LoggerFactoryUtils.getInstance().load(DmController.class);


    @RequestMapping("/dm")
    @ResponseBody
    public ResponseEntity<byte[]> handleControllerExecution(HttpMethod method,
                                                            @RequestParam(value = "data", required = false, defaultValue = ParameterObject.DEFAULT_CONTECT) String ctx,
                                                            @RequestParam(value = "format", required = false, defaultValue = "png") String format,
                                                            @RequestParam(value = "size", required = false, defaultValue = "128x64") String sizep,
                                                            @RequestBody(required = false) String requestStr) throws IOException {
        DmEntity e = new DmEntity();
        MediaType mt = MediaType.TEXT_PLAIN;

        if (!ParameterObject.hasText(requestStr)) {
            requestStr = "{}";
        }

        String encoding = StandardCharsets.UTF_8.name();
        if (method == HttpMethod.GET) {

//            encoding = !encoding.isEmpty() ? encoding : StandardCharsets.UTF_8.name();
            ctx = URLDecoder.decode(ctx, encoding);
            ctx = new String(ctx.getBytes(encoding), StandardCharsets.ISO_8859_1);
            e.setData(ctx);

            if (format.contains("|")) {
                String[] f = format.split("\\|");
                format = f[0];
                e.setNeedBase64(f[1].toLowerCase().equalsIgnoreCase("base64"));
            } else {
                e.setNeedBase64(false);
            }
            e.setFormat(format);
            if (sizep.contains("x")) {
                String[] sizea = sizep.split("x");
                if (ZxingValidation.isNum(sizea[0]) && ZxingValidation.isNum(sizea[1])) {
                    e.setWidth(Integer.parseInt(sizea[0]));
                    e.setHeight(Integer.parseInt(sizea[1]));
                }
            }

            log.info(new Gson().toJson(e));
        } else if (method == HttpMethod.POST) {
            //BufferedReader br = new BufferedReader(new InputStreamReader(requestIS, encoding));
            Gson gson = new Gson();
            e = gson.fromJson(requestStr, DmEntity.class);
            if (!ParameterObject.hasText(e.getData())) {
                e.setData(ParameterObject.DEFAULT_CONTECT);
            }
            if (!ParameterObject.hasText(e.getFormat())) {
                e.setFormat("png");
            }
            if (!ParameterObject.hasInteger(e.getWidth()) || !ParameterObject.hasInteger(e.getWidth())) {
                e.setHeight(128);
                e.setWidth(128);
            }
            if (!ParameterObject.hasBoolean(e.isNeedBase64())) {
                e.setNeedBase64(false);
            }
            log.info(gson.toJson(e));
        } else {
            return ResponseUtils.sendErrorOverJSON(HttpStatus.NOT_IMPLEMENTED, "Request error!!!");
        }

        ByteMatrix matrix = ZxingUtil.encode(e.getData());

        if ("svg".equalsIgnoreCase(e.getFormat())) {
            try {
                mt = MediaType.parseMediaType("image/svg+xml");

                ByteArrayOutputStream out = new ByteArrayOutputStream();
                ZxingImage.toSVGDocument(matrix,
                        new OutputStreamWriter(new BufferedOutputStream(out), StandardCharsets.ISO_8859_1.name()),
                        new ImageEntity(e.getHeight(), e.getWidth(), 0, ZxingImage.BLACK, ZxingImage.WHITE));

                return ResponseUtils.sendOkContent(mt, out.toByteArray());
            } catch (Exception ex) {
                String errorMsg = "Create Fail!!!";
                if (log.isDebugEnabled()) {
                    log.error(errorMsg, ex);
                } else {
                    log.error(errorMsg);
                }
                return ResponseUtils.sendErrorOverJSON(HttpStatus.INTERNAL_SERVER_ERROR, errorMsg);
            }
        }

        ImageEntity img = new ImageEntity();
        img.setHeight(e.getHeight());
        img.setMargin(1);
        img.setWidth(e.getWidth());
        img.setFgColor(ZxingImage.BLACK);
        img.setBgColor(ZxingImage.WHITE);

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        if (!ImageIO.write(ZxingImage.toBufferedImage(matrix, img), e.getFormat().toLowerCase(), out)) {
            String errmsg = "Could not write an image of format " + e.getFormat().toLowerCase();
            log.error(errmsg);
            return ResponseUtils.sendErrorOverJSON(HttpStatus.INTERNAL_SERVER_ERROR, errmsg);
        }
        if (e.isNeedBase64()) {
            String base64 = Base64.encodeToString(out.toByteArray());

            return ResponseUtils.sendOkContent(mt, base64.getBytes());
        } else {
            if (e.getFormat().equalsIgnoreCase("png")) {
                mt = MediaType.IMAGE_PNG;
            } else if (e.getFormat().equalsIgnoreCase("gif")) {
                mt = MediaType.IMAGE_GIF;
            } else if (e.getFormat().equalsIgnoreCase("jpg") || e.getFormat().equalsIgnoreCase("jpeg")) {
                mt = MediaType.IMAGE_JPEG;
            } else {
                return ResponseUtils.sendErrorOverJSON(HttpStatus.NOT_IMPLEMENTED, "Not implement image");
            }

            return ResponseUtils.sendOkContent(mt, out.toByteArray());
        }
    }
}
